package run;

import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.*;
import java.io.File;
import java.util.Comparator;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableRowSorter;
import vkmc.Actions;
import vkmc.Settings;

@SuppressWarnings({ "serial" })
public class Gui extends JFrame
{
	public Gui instance;
	public Actions actions;
	private DefaultTableModel tmodel;
	private DefaultTableModel tmodel2;
	private String[][] data;
	private JScrollPane jsp;
	private JScrollPane jsp2;
	@SuppressWarnings("rawtypes")
	private TableRowSorter sorter;
	private boolean firstSorted;

	private JTable table;
	private JTextField searchBar;
	private JButton searchBtn;
	private JTable downloading;
	private JLabel searchLbl;
	private JLabel downloadsLbl;
	private JPanel iconLbl;

	private JMenuBar menubar;
	private JPopupMenu downloadingMenu;
	private JPopupMenu searchMenu;

	private GridBagLayout layout;
	private GridBagConstraints gbc;

	private final String[] cols = new String[] {
			LanguageLoader.currentLang.language.tableColumns.name,
			LanguageLoader.currentLang.language.tableColumns.length,
			LanguageLoader.currentLang.language.tableColumns.bitrate,
			LanguageLoader.currentLang.language.tableColumns.size,
			"Url"
	};

	private final ImageIcon[] icons = new ImageIcon[16];
	private Timer busyTimer;
	private int iconIndex;
	
	@SuppressWarnings("rawtypes")
	public Gui(String titolo, int w, int h, boolean visible)
	{
		// -----------------------------------------------------------------------
		super(titolo);
		instance = this;
		setSize(w, h);
		setLocation(100, 100);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		layout = new GridBagLayout();
		setLayout(layout);
		gbc = new GridBagConstraints();
		// -----------------------------------------------------------------------

		java.net.URL imgURL = getClass().getResource("/res/icon.png");
		ImageIcon icon = new ImageIcon(imgURL);
		
		for (int i = 0; i < 15; i++)
		{
			imgURL = getClass().getResource("/res/busy-icon" + i + ".png");
			icons[i] = new ImageIcon(imgURL);
		}
		
		imgURL = getClass().getResource("/res/idle-icon.png");
		icons[15] = new ImageIcon(imgURL);
		
		iconIndex = 15;
		
		busyTimer = new Timer(30, new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				if (iconIndex < 15)
					iconIndex++;
				else
					iconIndex = 0;
				iconLbl.repaint();
			}
		});
		
		setIconImage(icon.getImage());
		
		sorter = new TableRowSorter();
		firstSorted = false;
		
		setupMenu();

		initComponents();
		setupLayout();

		actions = new Actions();

		// -----------------------------------------------------------------------
		setVisible(visible);
	}

    public void toggleSearchBtn(boolean enabled){
        searchBtn.setEnabled(enabled);
    }
	
	public void startBusyAnimation()
	{
		iconIndex = 0;
		busyTimer.start();
	}
	
	public void stopBusyAnimation()
	{
		busyTimer.stop();
		iconIndex = 15;
		iconLbl.repaint();
	}

	public void setupMenu()
	{
		menubar = new JMenuBar();

		JMenu mSettings = new JMenu(LanguageLoader.currentLang.language.menuNames.settings);
		JMenu mHelp = new JMenu("?");

		JMenuItem miPrefs = new JMenuItem(LanguageLoader.currentLang.language.settingsMenu.preferences);
		miPrefs.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				new SettingsForm(instance);
			}
		});
		JMenuItem miExit = new JMenuItem(LanguageLoader.currentLang.language.settingsMenu.exit);
		miExit.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				System.exit(0);
			}
		});
		
		JMenuItem miAbout = new JMenuItem(LanguageLoader.currentLang.language.helpMenu.about + " VKMediaCrawler");
		miAbout.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				new AboutForm(instance);
			}
		});

		mSettings.add(miPrefs);
		mSettings.addSeparator();
		mSettings.add(miExit);
		
		mHelp.add(miAbout);

		menubar.add(mSettings);
		menubar.add(mHelp);

		setJMenuBar(menubar);

		downloadingMenu = new JPopupMenu();
		JMenuItem miCancel = new JMenuItem(LanguageLoader.currentLang.language.downloadsListMenu.cancel);
		miCancel.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				int s = downloading.getSelectedRow();
				if (s >= 0)
					actions.cancelDownload(s);
			}
		});
		downloadingMenu.add(miCancel);

		JMenuItem miOpenFolder = new JMenuItem(LanguageLoader.currentLang.language.downloadsListMenu.openFolder);
		miOpenFolder.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				int s = downloading.getSelectedRow();
				if (s >= 0 && Desktop.isDesktopSupported())
				{
					try
					{
						Desktop.getDesktop().open(new File(Settings.getDownloadDirectory()));
					}
					catch (Exception ex)
					{}
				}
			}
		});
		downloadingMenu.add(miOpenFolder);

		searchMenu = new JPopupMenu();
		JMenuItem miDownload = new JMenuItem(LanguageLoader.currentLang.language.searchListMenu.download);
		miDownload.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				int s = table.getSelectedRow();
				if (s >= 0)
				{
					tmodel2.addRow(new Object[] { (String) table.getValueAt(s, table.getColumn(LanguageLoader.currentLang.language.tableColumns.name).getModelIndex()), 0 });
					actions.download((String) table.getValueAt(s, table.getColumn("Url").getModelIndex()), (String) table.getValueAt(s, table.getColumn(LanguageLoader.currentLang.language.tableColumns.name).getModelIndex()), tmodel2.getRowCount() - 1);
				}
			}
		});
		searchMenu.add(miDownload);
		JMenuItem miShowUrl = new JMenuItem(LanguageLoader.currentLang.language.searchListMenu.copyUrl);
		miShowUrl.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				int s = table.getSelectedRow();
				if (s >= 0)
				{
					String url = (String)table.getValueAt(s, table.getColumn("Url").getModelIndex());
					Toolkit toolkit = Toolkit.getDefaultToolkit();
					Clipboard clipboard = toolkit.getSystemClipboard();
					StringSelection strSel = new StringSelection(url);
					clipboard.setContents(strSel, null);
				}
			}
		});
		searchMenu.add(miShowUrl);
	}

	public void setData(String[][] data)
	{
		searchBtn.setEnabled(true);
		searchBar.setEnabled(true);
		table.setEnabled(true);
		downloading.setEnabled(true);
		this.data = data;
		createTable();
		stopBusyAnimation();
	}

	public void setProgress(int progress, int row)
	{
		downloading.setValueAt(progress, row, downloading.getColumn(LanguageLoader.currentLang.language.tableColumns.progress).getModelIndex());
	}

	@SuppressWarnings({ "unchecked" })
	private void initTable()
	{
		table = new JTable(new DefaultTableModel(cols, 0))
		{
			public boolean isCellEditable(int data, int column)
			{
				return false;
			}

			public Component prepareRenderer(TableCellRenderer r, int data, int columns)
			{
				Component c = super.prepareRenderer(r, data, columns);
				if (data % 2 == 0)
					c.setBackground(new Color(245, 245, 245));
				else
					c.setBackground(new Color(255, 255, 255));

				if (isCellSelected(data, columns))
                    c.setBackground(new Color(210, 210, 210));

				return c;
			}
		};
		table.getTableHeader().setReorderingAllowed(false);
		table.setFont(new Font("Arial", Font.PLAIN, 16));
		table.setPreferredScrollableViewportSize(new Dimension(500, 600));
		table.setFillsViewportHeight(true);
		table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		jsp = new JScrollPane(table);

		tmodel = (DefaultTableModel) table.getModel();
		table.getColumn(cols[0]).setPreferredWidth(500);
		table.getColumn(cols[1]).setPreferredWidth(100);
		table.getColumn(cols[2]).setPreferredWidth(100);
		table.getColumn(cols[3]).setPreferredWidth(100);
		table.getColumn(cols[4]).setMinWidth(0);
		table.getColumn(cols[4]).setMaxWidth(0);
		table.getColumn(cols[4]).setWidth(0);

		table.setRowSorter(sorter);
		sorter.setModel(table.getModel());
		sorter.setComparator(table.getColumn(LanguageLoader.currentLang.language.tableColumns.name).getModelIndex(), new StringSorter());
		sorter.setComparator(table.getColumn(LanguageLoader.currentLang.language.tableColumns.length).getModelIndex(), new TimeStringSorter());
		sorter.setComparator(table.getColumn(LanguageLoader.currentLang.language.tableColumns.bitrate).getModelIndex(), new NumericStringSorter());
		sorter.setComparator(table.getColumn(LanguageLoader.currentLang.language.tableColumns.size).getModelIndex(), new SizeSorter());
		
		table.addMouseListener(new MouseAdapter()
		{
			public void mousePressed(MouseEvent e)
			{
				int s = table.getSelectedRow();
				if (s >= 0 && e.getButton() == MouseEvent.BUTTON3)
				{
					searchMenu.show(table, e.getX(), e.getY());
					return;
				}
				if (s >= 0 && e.getClickCount() == 2)
				{
					tmodel2.addRow(new Object[] { (String) table.getValueAt(s, table.getColumn(LanguageLoader.currentLang.language.tableColumns.name).getModelIndex()), 0 });
					actions.download((String) table.getValueAt(s, table.getColumn("Url").getModelIndex()), (String) table.getValueAt(s, table.getColumn(LanguageLoader.currentLang.language.tableColumns.name).getModelIndex()), tmodel2.getRowCount() - 1);
				}
			}
		});

		// TABLE 2
		downloading = new JTable(new DefaultTableModel(new String[] { LanguageLoader.currentLang.language.tableColumns.name, LanguageLoader.currentLang.language.tableColumns.progress }, 0))
		{
			public boolean isCellEditable(int data, int column)
			{
				return false;
			}

			public Component prepareRenderer(TableCellRenderer r, int data, int columns)
			{
				Component c = super.prepareRenderer(r, data, columns);
				if (data % 2 == 0)
					c.setBackground(new Color(245, 245, 245));
				else
					c.setBackground(new Color(255, 255, 255));

				if (isCellSelected(data, columns))
                    c.setBackground(new Color(210, 210, 210));

				return c;
			}
		};
		downloading.getTableHeader().setReorderingAllowed(false);
		downloading.setFont(new Font("Arial", Font.PLAIN, 16));
		downloading.setPreferredScrollableViewportSize(new Dimension(300, 100));
		downloading.setFillsViewportHeight(true);
		downloading.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		jsp2 = new JScrollPane(downloading);

		tmodel2 = (DefaultTableModel) downloading.getModel();
		
		downloading.addMouseListener(new MouseAdapter()
		{
			public void mousePressed(MouseEvent e)
			{
				int s = downloading.getSelectedRow();
				if (s >= 0 && e.getButton() == MouseEvent.BUTTON3)
				{
					downloadingMenu.show(downloading, e.getX(), e.getY());
					return;
				}
				if (s >= 0 && e.getClickCount() == 2)
					actions.cancelDownload(s);
			}
		});
		downloading.getColumn(LanguageLoader.currentLang.language.tableColumns.progress).setCellRenderer(new ProgressRenderer());
	}

	private void search()
	{
		startBusyAnimation();
		tmodel.setRowCount(0);
		searchBtn.setEnabled(false);
		searchBar.setEnabled(false);
		table.setEnabled(false);
		downloading.setEnabled(false);
		if (!actions.loggedIn())
		{
			actions.login();
			return;
		}
		actions.setSearchKey(searchBar.getText());
		actions.Search();
	}
	
	public void startSearch()
	{
		search();
	}
	
	private void initComponents()
	{
		ActionListener l = new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				search();
			}
		};
		initTable();
		searchBar = new JTextField();
		searchBar.addActionListener(l);
		searchBtn = new JButton(LanguageLoader.currentLang.language.mainGui.search);
		searchBtn.addActionListener(l);
		searchLbl = new JLabel("  " + LanguageLoader.currentLang.language.mainGui.search + ": ");
		downloadsLbl = new JLabel("  " + LanguageLoader.currentLang.language.mainGui.downloads + ": ");
		iconLbl = new JPanel(){
			public void paintComponent(Graphics g)
			{
				super.paintComponent(g);
				g.drawImage(icons[iconIndex].getImage(), 0, 0, null);
			}
		};
		iconLbl.setDoubleBuffered(true);
	}

	private void setupLayout()
	{
		gbc.gridx = 0;
		gbc.gridy = 0;
		gbc.gridwidth = 1;
		gbc.gridheight = 1;
		gbc.weightx = 0;
		gbc.weighty = 0;
		gbc.ipadx = 25;
		gbc.fill = GridBagConstraints.BOTH;
		layout.setConstraints(searchLbl, gbc);
		add(searchLbl);

		gbc.gridx = 1;
		gbc.gridy = 0;
		gbc.gridwidth = 1;
		gbc.gridheight = 1;
		gbc.weightx = 1.0;
		gbc.weighty = 0;
		gbc.ipadx = 550;
		gbc.fill = GridBagConstraints.BOTH;
		layout.setConstraints(searchBar, gbc);
		add(searchBar);

		gbc.gridx = 2;
		gbc.gridy = 0;
		gbc.gridwidth = 1;
		gbc.gridheight = 1;
		gbc.weightx = 0;
		gbc.weighty = 0;
		gbc.ipadx = 100;
		gbc.fill = GridBagConstraints.BOTH;
		layout.setConstraints(searchBtn, gbc);
		add(searchBtn);
		
		gbc.gridx = 3;
		gbc.gridy = 0;
		gbc.gridwidth = 1;
		gbc.gridheight = 1;
		gbc.weightx = 0;
		gbc.weighty = 0;
		gbc.ipadx = 16;
		gbc.insets = new Insets(5, 5, 0, 0);
		gbc.fill = GridBagConstraints.BOTH;
		layout.setConstraints(iconLbl, gbc);
		add(iconLbl);

		gbc.insets = new Insets(0, 0, 0, 0);
		gbc.gridx = 0;
		gbc.gridy = 1;
		gbc.gridwidth = 4;
		gbc.gridheight = 1;
		gbc.weightx = 1.0;
		gbc.weighty = 1.0;
		gbc.ipady = 400;
		gbc.fill = GridBagConstraints.BOTH;
		layout.setConstraints(jsp, gbc);
		add(jsp);

		gbc.gridx = 0;
		gbc.gridy = 2;
		gbc.gridwidth = 4;
		gbc.gridheight = 1;
		gbc.weightx = 0;
		gbc.weighty = 0;
		gbc.ipadx = getWidth();
		gbc.ipady = 0;
		gbc.insets = new Insets(5, 0, 5, 0);
		gbc.fill = GridBagConstraints.BOTH;
		layout.setConstraints(downloadsLbl, gbc);
		add(downloadsLbl);

		gbc.gridx = 0;
		gbc.gridy = 3;
		gbc.gridwidth = 4;
		gbc.gridheight = 1;
		gbc.weightx = 1.0;
		gbc.weighty = 0;
		gbc.ipady = 200;
		gbc.insets = new Insets(0, 0, 5, 0);
		gbc.fill = GridBagConstraints.BOTH;
		layout.setConstraints(jsp2, gbc);
		add(jsp2);
	}

	public void createTable()
	{
		tmodel.setRowCount(0);
		for (String[] d : data)
		{
			tmodel.addRow(d);
		}
		if (!firstSorted)
		{
			sorter.toggleSortOrder(table.getColumn(LanguageLoader.currentLang.language.tableColumns.name).getModelIndex());
			firstSorted = true;
		}
	}

	class ProgressRenderer extends DefaultTableCellRenderer
	{
		private final JProgressBar b = new JProgressBar(0, 100);

		public ProgressRenderer()
		{
			super();
			setOpaque(true);
			b.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
		}

		public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
		{
			Integer i = (Integer) value;
			String text = LanguageLoader.currentLang.language.tableColumns.done;
			if (i < 0)
			{
				text = LanguageLoader.currentLang.language.tableColumns.canceled;
			}
			else if (i < 100)
			{
				b.setValue(i);
				return b;
			}
			super.getTableCellRendererComponent(table, text, isSelected, hasFocus, row, column);
			return this;
		}
	}
	
	class NumericSorter implements Comparator<Integer>
	{
		public NumericSorter(){}
		
		public int compare(Integer n1, Integer n2)
		{
			return (n1 < n2 ? -1 : (n1 > n2 ? 1 : 0));
		}
	}

	class NumericStringSorter implements Comparator<String>
	{
		public NumericStringSorter(){}
		
		public int compare(String a, String b)
		{
			if (std.isNumeric(a) && std.isNumeric(b))
			{
				int n1 = std.toint(a);
				int n2 = std.toint(b);
				return (n1 < n2 ? -1 : (n1 > n2 ? 1 : 0));
			}
			return -1;
		}
	}
	
	class SizeSorter implements Comparator<String>
	{
		public SizeSorter(){}
		
		public int compare(String a, String b)
		{
			if (a.trim().toLowerCase().endsWith("B"))
			{
				if (!b.trim().toLowerCase().endsWith("B"))
					return -1;
			}
			else if (a.trim().toLowerCase().endsWith("KB"))
			{
				if (b.trim().toLowerCase().endsWith("B"))
					return 1;
				if (b.trim().toLowerCase().endsWith("MB"))
					return -1;
				if (b.trim().toLowerCase().endsWith("GB"))
					return -1;
			}
			else if (a.trim().toLowerCase().endsWith("MB"))
			{
				if (b.trim().toLowerCase().endsWith("B"))
					return 1;
				if (b.trim().toLowerCase().endsWith("KB"))
					return 1;
				if (b.trim().toLowerCase().endsWith("GB"))
					return -1;
			}
			else if (a.trim().toLowerCase().endsWith("GB"))
			{
				if (!b.trim().toLowerCase().endsWith("GB"))
					return -1;
			}
			if (a.trim().contains(" ") && b.trim().contains(" "))
			{
				a = a.replace(",", ".").trim();
				b = b.replace(",", ".").trim();
				float n1 = Float.parseFloat(a.substring(0, a.indexOf(" ")));
				float n2 = Float.parseFloat(b.substring(0, b.indexOf(" ")));
				return (n1 < n2 ? -1 : (n1 > n2 ? 1 : 0));
			}
			return -1;
		}
	}
	
	class TimeStringSorter implements Comparator<String>
	{
		public TimeStringSorter(){}

		public int compare(String a, String b)
		{
			if (a.contains(":") && b.contains(":"))
			{
				String[] t1 = a.split(":");
				String[] t2 = b.split(":");
				if (t1.length != 2 && t2.length != 2)
					return -1;
				if (std.isNumeric(t1[0]) && std.isNumeric(t1[1]) && std.isNumeric(t2[0]) && std.isNumeric(t2[1]))
				{
					int n11 = std.toint(t1[0]);
					int n12 = std.toint(t1[1]);
					int n21 = std.toint(t2[0]);
					int n22 = std.toint(t2[1]);
					
					if (n11 < n21)
						return -1;
					if (n11 > n21)
						return 1;
					
					if (n12 < n22)
						return -1;
					if (n12 > n22)
						return 1;
					
					return 0;
				}
			}
			return -1;
		}
	}
	
	class StringSorter implements Comparator<String>
	{
		public StringSorter(){}

		public int compare(String a, String b)
		{
			return a.compareToIgnoreCase(b);
		}
	}
}
